package com.chuangke.flow.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chuangke.common.constant.Masks;
import com.chuangke.common.enums.OrderStatusEnum;
import com.chuangke.common.exception.ChuangkeException;
import com.chuangke.common.express.CkEvaluatorExecutor;
import com.chuangke.common.idgen.IdManager;
import com.chuangke.common.utils.SpringContextUtil;
import com.chuangke.flow.constant.FlowConstant;
import com.chuangke.flow.dao.FlowHiFlowDao;
import com.chuangke.flow.dao.FlowHiNodeDao;
import com.chuangke.flow.dao.FlowHiNodeProcessorDao;
import com.chuangke.flow.dao.FlowHiTaskDao;
import com.chuangke.flow.dao.FlowHiTaskLogDao;
import com.chuangke.flow.dao.FlowHiVariableDao;
import com.chuangke.flow.dao.FlowRuFlowDao;
import com.chuangke.flow.dao.FlowRuNodeDao;
import com.chuangke.flow.dao.FlowRuNodeProcessorDao;
import com.chuangke.flow.dao.FlowRuTaskDao;
import com.chuangke.flow.dao.FlowRuVariableDao;
import com.chuangke.flow.domain.FlowStartData;
import com.chuangke.flow.domain.OrderModel;
import com.chuangke.flow.entity.FlowHiFlow;
import com.chuangke.flow.entity.FlowHiNode;
import com.chuangke.flow.entity.FlowHiNodeProcessor;
import com.chuangke.flow.entity.FlowHiTask;
import com.chuangke.flow.entity.FlowHiTaskLog;
import com.chuangke.flow.entity.FlowHiVariable;
import com.chuangke.flow.entity.FlowMdFlow;
import com.chuangke.flow.entity.FlowRuFlow;
import com.chuangke.flow.entity.FlowRuNode;
import com.chuangke.flow.entity.FlowRuNodeProcessor;
import com.chuangke.flow.entity.FlowRuTask;
import com.chuangke.flow.entity.FlowRuVariable;
import com.chuangke.flow.enums.FlowNodeStatusEnum;
import com.chuangke.flow.plugin.FlowGetTaskUser;
import com.chuangke.flow.service.FlowDefineService;
import com.chuangke.flow.service.FlowInstanceService;
import com.chuangke.flow.util.FlowModelUtils;
import com.chuangke.flow.util.FlowUtils;
import com.chuangke.metadata.entity.SysBill;
import com.chuangke.metadata.service.SysBillService;

import cn.hutool.core.util.StrUtil;

@Service
public class FlowInstanceServiceImpl implements FlowInstanceService {

    @Autowired
    private FlowDefineService flowDefineService;

    @Autowired
    private FlowRuFlowDao flowRuFlowDao;
    @Autowired
    private FlowRuNodeDao flowRuNodeDao;
    @Autowired
    private FlowRuNodeProcessorDao flowRuNodeProcessorDao;
    @Autowired
    private FlowRuTaskDao flowRuTaskDao;
    @Autowired
    private FlowRuVariableDao flowRuVariableDao;

    @Autowired
    private FlowHiFlowDao flowHiFlowDao;
    @Autowired
    private FlowHiNodeDao flowHiNodeDao;
    @Autowired
    private FlowHiNodeProcessorDao flowHiNodeProcessorDao;
    @Autowired
    private FlowHiTaskDao flowHiTaskDao;
    @Autowired
    private FlowHiTaskLogDao flowHiTaskLogDao;
    @Autowired
    private FlowHiVariableDao flowHiVariableDao;
    
    @Autowired
	private SysBillService sysBillService;

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void startInstanceByFlowId(String flowId, List<OrderModel> orderModelList) {
        if (CollectionUtils.isEmpty(orderModelList)) {
            return;
        }

        List<FlowRuFlow> ruFlowList = new ArrayList<>();
        List<FlowRuNode> nodeList = new ArrayList<>();
        List<FlowRuNodeProcessor> processors = new ArrayList<>();
        List<FlowRuVariable> varList = new ArrayList<>();
        List<FlowRuTask> taskList = new ArrayList<>();

        orderModelList.forEach(orderModel -> {
            // 初始化流程实例
            FlowStartData fsd = initInstanceByDefinition(flowId, orderModel, orderModel.getVariables());

            // 初始化子流程实例
            Map<String,FlowStartData> subFlowMap = new HashMap<>() ;
            FlowRuFlow currentRuFlow = fsd.getRuFlowList().get(0) ;
            initSubInstanceByDefinition(subFlowMap,currentRuFlow.getId(),orderModel,fsd.getNodeList()) ;

            // 生成任务
            List<FlowRuTask> processTaskList = generateInstanceTask(subFlowMap,fsd.getNodeList(), orderModel, orderModel.getVariables()) ;

            ruFlowList.addAll(fsd.getRuFlowList());
            nodeList.addAll(fsd.getNodeList());
            processors.addAll(fsd.getProcessors());
            varList.addAll(fsd.getVarList());
            taskList.addAll(processTaskList);

           
            subFlowMap.values().forEach(subfsd -> {
                nodeList.addAll(subfsd.getNodeList());
                processors.addAll(subfsd.getProcessors());
            });
        });

        doSaveRuAndHiInfo(ruFlowList, nodeList, processors, varList, taskList);
    }

    /**
     * 循环遍历nodeList，寻找子流程节点，并创建实例信息
     * @param subFlowMap
     * @param ruFlowId
     * @param orderModel
     * @param nodeList
     */
    private void initSubInstanceByDefinition(Map<String,FlowStartData> subFlowMap, String ruFlowId, OrderModel orderModel, List<FlowRuNode> nodeList){
    	for(FlowRuNode node : nodeList){
            if(!FlowConstant.LOGIC_NODE_TYPE_SUBFLOW.equals(node.getType())){
                continue;
            }
            
            FlowStartData subFsd = initInstanceByDefinition(node.getContent(), orderModel, orderModel.getVariables());
            
            if(!CollectionUtils.isEmpty(subFsd.getNodeList())) {
            	subFsd.getNodeList().forEach(subNode -> subNode.setFlowId(ruFlowId)) ;
            }
            
            if(!CollectionUtils.isEmpty(subFsd.getProcessors())) {
            	subFsd.getProcessors().forEach(processor -> processor.setFlowId(ruFlowId)) ;
            }

            subFlowMap.put(node.getContent(),subFsd) ;
            
            //循环初始化子流程的子流程
            initSubInstanceByDefinition(subFlowMap,ruFlowId,orderModel,subFsd.getNodeList()) ;
        }
    }

    /**
     * 根据流程定义创建流程实例
     * @param flowId
     * @param orderModel
     * @param variables
     * @return
     */
    private FlowStartData initInstanceByDefinition(String flowId, OrderModel orderModel, Map<String, Object> variables) {
        FlowMdFlow mdFlow = flowDefineService.load(flowId);

        FlowRuFlow ruFlow = getRuFlow(mdFlow, orderModel);
        List<FlowRuFlow> ruFlowList = Arrays.asList(ruFlow) ;
        List<FlowRuNode> nodeList = getRuNodeList(ruFlow);
        List<FlowRuNodeProcessor> processors = getRuProcessorList(nodeList);
        List<FlowRuVariable> varList = getRuVarList(ruFlow, variables);

        FlowStartData fsd = new FlowStartData();
        fsd.setRuFlowList(ruFlowList);
        fsd.setNodeList(nodeList);
        fsd.setProcessors(processors);
        fsd.setVarList(varList);

        return fsd;
    }

    /**
     * 将流程信息同步到历史表中
     *
     * @param nodeList
     * @param processors
     * @param varList
     * @param taskList
     */
    private void doSaveRuAndHiInfo(List<FlowRuFlow> ruFlowList, List<FlowRuNode> nodeList, List<FlowRuNodeProcessor> processors,
                        List<FlowRuVariable> varList, List<FlowRuTask> taskList) {
        // 插入运行表中
        flowRuFlowDao.insertBatchSomeColumn(ruFlowList);
        flowRuNodeDao.insertBatchSomeColumn(nodeList);
        flowRuNodeProcessorDao.insertBatchSomeColumn(processors);
        flowRuVariableDao.insertBatchSomeColumn(varList);
        flowRuTaskDao.insertBatchSomeColumn(taskList);
        
        // 插入历史表中
        List<FlowHiFlow> hiFlowList = ruFlowList.stream().map(ruFlow -> {
            FlowHiFlow hiFlow = FlowModelUtils.convertRH(ruFlow);
            hiFlow.setOrderStatus(OrderStatusEnum.EDIT.getCode());
            return hiFlow;
        }).collect(Collectors.toList());
        flowHiFlowDao.insertBatchSomeColumn(hiFlowList);
        
        List<FlowHiNode> hiNodeList = nodeList.stream().map(FlowModelUtils::convertRH)
                .collect(Collectors.toList());
        flowHiNodeDao.insertBatchSomeColumn(hiNodeList);
        
        List<FlowHiNodeProcessor> hiProcessors = processors.stream()
                .map(FlowModelUtils::convertRH).collect(Collectors.toList());
        flowHiNodeProcessorDao.insertBatchSomeColumn(hiProcessors);
        
        List<FlowHiVariable> hiVarList = varList.stream().map(FlowModelUtils::convertRH)
                .collect(Collectors.toList());
        flowHiVariableDao.insertBatchSomeColumn(hiVarList);
        
        List<FlowHiTask> hiTaskList = taskList.stream().map(FlowModelUtils::convertRH)
                .collect(Collectors.toList());
        flowHiTaskDao.insertBatchSomeColumn(hiTaskList);

        List<FlowRuTask> firstTaskList = taskList.stream().filter(task -> task.getOrderNum() == 1)
                .collect(Collectors.toList());
        FlowUtils.startTaskInHistory(flowHiTaskLogDao,firstTaskList);
    }

    private FlowRuFlow getRuFlow(FlowMdFlow mdFlow, OrderModel orderModel) {
        FlowRuFlow ruFlow = FlowModelUtils.convert(mdFlow);
        ruFlow.setId(IdManager.nextId());
        ruFlow.setMdFlowId(mdFlow.getId());
        try {
            BeanUtils.copyProperties(ruFlow, orderModel);
        } catch (Exception e) {
            throw new ChuangkeException(e);
        }
        return ruFlow;
    }

    private List<FlowRuNode> getRuNodeList(FlowRuFlow ruFlow) {
        ruFlow.getNodes().forEach(node -> {
            node.setFlowId(ruFlow.getId());
            node.setOrderId(ruFlow.getOrderId());
        });
        return ruFlow.getNodes();
    }

    private List<FlowRuNodeProcessor> getRuProcessorList(List<FlowRuNode> nodeList) {
        List<FlowRuNodeProcessor> processors = new ArrayList<>();
        nodeList.forEach(node -> {
            if (CollectionUtils.isNotEmpty(node.getProcessors())) {
                node.getProcessors().forEach(processor -> {
                    processor.setId(IdManager.nextId());
                    processor.setFlowId(node.getFlowId());
                    processor.setNodeId(node.getId());
                    processor.setOrderId(node.getOrderId());

                    processors.add(processor);
                });
            }
        });
        return processors;
    }

    private List<FlowRuVariable> getRuVarList(FlowRuFlow ruFlow, Map<String, Object> variables) {
        List<FlowRuVariable> varList = new ArrayList<>();
        if (variables != null) {
            for (String key : variables.keySet()) {
                Object value = variables.get(key);
                if (value == null) {
                    continue;
                }
                FlowRuVariable var = new FlowRuVariable();
                var.setFlowId(ruFlow.getId());
                var.setId(IdManager.nextId());
                var.setOrderId(ruFlow.getOrderId());
                var.setType(value.getClass().getName());
                var.setName(key);
                var.setValue(value.toString());
                varList.add(var);
            }
        }
        return varList;
    }

    private List<FlowRuTask> generateInstanceTask(Map<String,FlowStartData> subFlowMap, List<FlowRuNode> nodeList, OrderModel orderModel,
                                                 Map<String, Object> variables) {
        FlowRuNode nodeTree = buildInstanceNodeTree(subFlowMap,nodeList,variables) ;

        return generateTasks(orderModel,nodeTree);
    }

    private List<FlowRuTask> generateTasks(OrderModel orderModel,FlowRuNode treeNode){
        AtomicInteger taskOrder = new AtomicInteger() ;
        List<FlowRuTask> taskList = new ArrayList<>();
        generateTasks(Arrays.asList(treeNode), taskList, orderModel, taskOrder);
        taskList.forEach(task -> {
            if (task.getOrderNum() == 1) {
                task.status(FlowNodeStatusEnum.unhandle.getCode()).startAt(new Date());
            }
            task.setType(FlowConstant.TASK_TYPE_APPROVAL);
        });
        return taskList;
    }

    /**
     * 生成流程的所有任务
     *
     * @param nextNodes
     * @param taskList
     * @param orderModel
     * @param taskOrder
     */
    private void generateTasks(List<FlowRuNode> nextNodes, List<FlowRuTask> taskList, OrderModel orderModel,
                               AtomicInteger taskOrder) {
        if (CollectionUtils.isEmpty(nextNodes)) {
            return;
        }

        for(FlowRuNode node : nextNodes){
            taskList.addAll(getTasksByNode(node, orderModel, taskOrder.addAndGet(1)));

            if (CollectionUtils.isNotEmpty(node.getNextNodes())) {
                generateTasks(node.getNextNodes(), taskList, orderModel, taskOrder);
            }
        }
    }

    private FlowRuNode buildInstanceNodeTree(Map<String,FlowStartData> subFlowMap, List<FlowRuNode> nodeList, Map<String, Object> variables) {
        //获取开始节点
        FlowRuNode startNode = getStartNode(nodeList) ;

        //获取连线
        List<FlowRuNode> lineNodeList = nodeList.stream().filter(node -> node.getType().equals(FlowConstant.LOGIC_NODE_TYPE_LINE)).collect(Collectors.toList());

        //递归构建节点树
        constructNextNodes(subFlowMap,startNode,startNode,lineNodeList,nodeList,variables);

        return startNode;
    }

    private FlowRuNode getStartNode(List<FlowRuNode> nodeList){
        List<FlowRuNode> startNodeList = nodeList.stream().filter(node -> node.getType().equals(FlowConstant.LOGIC_NODE_TYPE_START)).collect(Collectors.toList());
        if (startNodeList.size() > 1) {
            throw new ChuangkeException("流程开始节点不能超过一个");
        }
        if(startNodeList.isEmpty()){
            throw new ChuangkeException("流程未定义开始节点");
        }

        FlowRuNode startNode = startNodeList.get(0) ;
        startNode.setIsPass(Masks.BOOL_YES);

        return startNode ;
    }

    /**
     * 递归构建子流程节点
     * @param subFlowMap
     * @param currentNode 流程走的节点
     * @param mountNode 挂载节点：要把后续的流程挂账的哪一个节点，主要是为解决子流程
     * @param lineNodeList
     * @param nodeList
     * @param variables
     */
    private void constructNextNodes(Map<String,FlowStartData> subFlowMap, FlowRuNode currentNode, FlowRuNode mountNode, List<FlowRuNode> lineNodeList, List<FlowRuNode> nodeList, Map<String, Object> variables){
        List<FlowRuNode> nextNodes = getNextNode(currentNode,lineNodeList,nodeList,variables) ;

        for(FlowRuNode nextNode : nextNodes){
            nextNode.setIsPass(Masks.BOOL_YES);

            if(FlowConstant.LOGIC_NODE_TYPE_END.equals(nextNode.getType())){
                continue ;
            }

            //子流程节点处理
            if(FlowConstant.LOGIC_NODE_TYPE_SUBFLOW.equals(nextNode.getType())){
                FlowStartData startData = subFlowMap.get(nextNode.getContent()) ;
                FlowRuNode startNode = buildInstanceNodeTree(subFlowMap,startData.getNodeList(),variables) ;

                mountNode.addAllNextNode(startNode.getNextNodes()) ;

                List<FlowRuNode> lastNodeList = new ArrayList<>() ;
                collectLastNode(lastNodeList,startNode.getNextNodes()) ;

                lastNodeList.forEach(node -> constructNextNodes(subFlowMap,nextNode,node,lineNodeList,nodeList,variables));
            }else {
                mountNode.addNextNode(nextNode);
                constructNextNodes(subFlowMap,nextNode,nextNode,lineNodeList,nodeList,variables);
            }
        }
    }

    private void collectLastNode(List<FlowRuNode> lastNodeList, List<FlowRuNode> nodeList){
        nodeList.forEach(node -> {
            if(node.getNextNodes().isEmpty()){
                lastNodeList.add(node) ;
            }else{
                collectLastNode(lastNodeList,node.getNextNodes()) ;
            }
        }) ;
    }

    private List<FlowRuNode> getNextNode(FlowRuNode node, List<FlowRuNode> lineNodeList, List<FlowRuNode> nodeList, Map<String, Object> variables){
        List<FlowRuNode> lineNodes = lineNodeList.stream().filter(line -> line.getPrevId().equals(node.getId())).collect(Collectors.toList()) ;

        List<FlowRuNode> nextNodes = new ArrayList<>() ;
        for(FlowRuNode lineNode : lineNodes){
            if(StrUtil.isNotBlank(lineNode.getContent())){
                // 判断当前分支节点是否满足条件
                Object result = CkEvaluatorExecutor.execute(lineNode.getContent(), variables);
                if (!(result instanceof Boolean)) {
                    throw new ChuangkeException(String.format("流程分支判断异常：判断结果(%s)", result));
                }
                Boolean b = (Boolean)result ;
                if (!b) {
                    continue;
                }
            }

            lineNode.setIsPass(Masks.BOOL_YES);

            Optional<FlowRuNode> nextNodeOption = nodeList.stream().filter(n -> n.getId().equals(lineNode.getNextId())).findFirst() ;
            if(nextNodeOption.get() == null){
                throw new ChuangkeException(String.format("流程节点【%s】分支异常：未找到下一节点",node.getTitle())) ;
            }

            FlowRuNode nextNode = nextNodeOption.get() ;
            if(FlowConstant.LOGIC_NODE_TYPE_CONDITION.equals(nextNode.getType())){
                nextNodes.addAll(getNextNode(nextNode,lineNodeList,nodeList,variables)) ;
            }else{
                nextNodes.add(nextNode);
            }
        }
        return nextNodes ;
    }

    /**
     * 根据节点审批信息，获取任务列表
     *
     * @param node
     * @param orderModel
     * @param orderNum
     * @return
     */
    private List<FlowRuTask> getTasksByNode(FlowRuNode node, OrderModel orderModel, int orderNum) {
        List<FlowRuTask> taskList = new ArrayList<>();

        /* 如果当前节点是审批人自己，直接从单据上获取制单人放到任务上 */
        if (FlowConstant.ASSIGNEE_TYPE_MYSELF.equals(node.getAssigneeType())) {
            FlowRuTask ruTask = new FlowRuTask();
            ruTask.id(IdManager.nextId()).flowId(node.getFlowId()).nodeId(node.getId()).orderId(orderModel.getOrderId())
                    .status(FlowNodeStatusEnum.unstart.getCode()).userId(orderModel.getOrderCreatedBy())
                    .orderNum(orderNum).createdAt(new Date()).createdBy("1").updatedAt(new Date()).updatedBy("1");
            taskList.add(ruTask);
            return taskList;
        }

        List<FlowRuNodeProcessor> processors = node.getProcessors();
        if (CollectionUtils.isEmpty(processors)) {
            throw new ChuangkeException(String.format("节点[%s]未找到审批人的相关配置", node.getTitle()));
        }

        /* 如果当前节点是审批人是角色，根据角色和单据的组织机构找到审批人 */
        if (FlowConstant.ASSIGNEE_TYPE_ROLE.equals(node.getAssigneeType())) {
            String userServiceBean = node.getUserService();
            String[] params = null ;
            userServiceBean = StrUtil.isBlank(userServiceBean) ? FlowConstant.DEFAULT_FLOW_GET_TASK_USER_SERVICE : userServiceBean;
            if(userServiceBean.contains("(")){
                params = userServiceBean.substring(0,userServiceBean.indexOf("(")).split(",") ;
                userServiceBean = userServiceBean.substring(userServiceBean.indexOf("(") + 1, userServiceBean.indexOf(")"));
            }

            List<String> userList = new ArrayList<>();
            FlowGetTaskUser sysDeptService;
            try {
                sysDeptService = SpringContextUtil.getBean(userServiceBean,
                        FlowGetTaskUser.class);
            } catch (Exception e) {
                throw new ChuangkeException(String.format("流程设置未找到用户加载服务[%s]", userServiceBean), e);
            }

            for (FlowRuNodeProcessor processor : processors) {
                List<String> taskUserList = sysDeptService.getTaskUser(node, processor, orderModel,params);
                if (CollectionUtils.isNotEmpty(taskUserList)) {
                    userList.addAll(taskUserList);
                }
            }

            if (CollectionUtils.isEmpty(userList)) {
                throw new ChuangkeException(
                        String.format("单据[%s]的节点[%s]根据角色未找到审批人", node.getOrderId(), node.getTitle()));
            }

            userList.forEach(user -> {
                FlowRuTask ruTask = new FlowRuTask();
                ruTask.id(IdManager.nextId()).flowId(node.getFlowId()).nodeId(node.getId())
                        .status(FlowNodeStatusEnum.unstart.getCode()).userId(user).orderNum(orderNum)
                        .orderId(orderModel.getOrderId()).createdAt(new Date()).createdBy("1").updatedAt(new Date())
                        .updatedBy("1");
                taskList.add(ruTask);
            });
        } else {
            processors.forEach(processor -> {
                FlowRuTask ruTask = new FlowRuTask();
                ruTask.id(IdManager.nextId()).flowId(node.getFlowId()).nodeId(node.getId())
                        .status(FlowNodeStatusEnum.unstart.getCode()).userId(processor.getProcessId())
                        .orderNum(orderNum).orderId(orderModel.getOrderId()).createdAt(new Date()).createdBy("1")
                        .updatedAt(new Date()).updatedBy("1");
                taskList.add(ruTask);
            });
        }

        return taskList;
    }

	@Override
    @Transactional(rollbackFor = Throwable.class)
	public void startInstanceByBillId(String billId, List<OrderModel> orderModelList) {
		SysBill bill = sysBillService.findById(billId) ;
		if(bill == null || StrUtil.isBlank(bill.getFlowId())) {
			throw new ChuangkeException(String.format("表单[%s]未配置流程信息", billId));
		}
		startInstanceByFlowId(bill.getFlowId(), orderModelList);
	}

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void deleteInstance(List<String> orderIdList) {
        if (CollectionUtils.isEmpty(orderIdList)) {
            return;
        }

        deleteRuFlowInfoByOrderId(orderIdList);
        deleteHiFlowInfoByOrderId(orderIdList);
    }

    @Async
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void deleteRuFlowInfoByOrderId(List<String> orderIdList) {
        flowRuFlowDao.remove(new QueryWrapper<FlowRuFlow>().lambda().in(FlowRuFlow::getOrderId, orderIdList));
        flowRuNodeDao.remove(new QueryWrapper<FlowRuNode>().lambda().in(FlowRuNode::getOrderId, orderIdList));
        flowRuNodeProcessorDao.remove(
                new QueryWrapper<FlowRuNodeProcessor>().lambda().in(FlowRuNodeProcessor::getOrderId, orderIdList));
        flowRuVariableDao
                .remove(new QueryWrapper<FlowRuVariable>().lambda().in(FlowRuVariable::getOrderId, orderIdList));
        flowRuTaskDao.remove(new QueryWrapper<FlowRuTask>().lambda().in(FlowRuTask::getOrderId, orderIdList));
    }

    private void deleteHiFlowInfoByOrderId(List<String> orderIdList) {
        flowHiFlowDao.remove(new QueryWrapper<FlowHiFlow>().lambda().in(FlowHiFlow::getOrderId, orderIdList));
        flowHiNodeDao.remove(new QueryWrapper<FlowHiNode>().lambda().in(FlowHiNode::getOrderId, orderIdList));
        flowHiNodeProcessorDao
                .remove(new QueryWrapper<FlowHiNodeProcessor>().lambda().in(FlowHiNodeProcessor::getOrderId, orderIdList));
        flowHiTaskDao.remove(new QueryWrapper<FlowHiTask>().lambda().in(FlowHiTask::getOrderId, orderIdList));
        flowHiVariableDao.remove(new QueryWrapper<FlowHiVariable>().lambda().in(FlowHiVariable::getOrderId, orderIdList));
        flowHiTaskLogDao.remove(new QueryWrapper<FlowHiTaskLog>().lambda().in(FlowHiTaskLog::getOrderId, orderIdList));
    }
    
    
    /**
     * 多线程不能启用,多线程会导致事务失败
     *
     * @param ruFlowList
     * @param nodeList
     * @param processors
     * @param varList
     * @param taskList
     */
    private void doStartConcurrent(List<FlowRuFlow> ruFlowList, List<FlowRuNode> nodeList,
                                  List<FlowRuNodeProcessor> processors, List<FlowRuVariable> varList, List<FlowRuTask> taskList) {

        @SuppressWarnings("rawtypes")
        List<CompletableFuture> futureList = new ArrayList<>();
        // 插入运行表中
        futureList.add(CompletableFuture.runAsync(() -> flowRuFlowDao.insertBatchSomeColumn(ruFlowList)));
        futureList.add(CompletableFuture.runAsync(() -> flowRuNodeDao.insertBatchSomeColumn(nodeList)));
        futureList.add(CompletableFuture.runAsync(() -> flowRuNodeProcessorDao.insertBatchSomeColumn(processors)));
        futureList.add(CompletableFuture.runAsync(() -> flowRuVariableDao.insertBatchSomeColumn(varList)));
        futureList.add(CompletableFuture.runAsync(() -> flowRuTaskDao.insertBatchSomeColumn(taskList)));

        // 插入历史表中
        if (CollectionUtils.isNotEmpty(ruFlowList)) {
            List<FlowHiFlow> hiFlowList = ruFlowList.stream().map(ruFlow -> {
                FlowHiFlow hiFlow = FlowModelUtils.convertRH(ruFlow);
                hiFlow.setOrderStatus(OrderStatusEnum.EDIT.getCode());
                return hiFlow;
            }).collect(Collectors.toList());

            futureList.add(CompletableFuture.runAsync(() -> flowHiFlowDao.insertBatchSomeColumn(hiFlowList)));
        }
        if (CollectionUtils.isNotEmpty(nodeList)) {
            List<FlowHiNode> hiNodeList = nodeList.stream().map(FlowModelUtils::convertRH)
                    .collect(Collectors.toList());
            futureList.add(CompletableFuture.runAsync(() -> flowHiNodeDao.insertBatchSomeColumn(hiNodeList)));
        }
        if (CollectionUtils.isNotEmpty(processors)) {
            List<FlowHiNodeProcessor> hiProcessors = processors.stream()
                    .map(FlowModelUtils::convertRH).collect(Collectors.toList());
            futureList.add(
                    CompletableFuture.runAsync(() -> flowHiNodeProcessorDao.insertBatchSomeColumn(hiProcessors)));
        }
        if (CollectionUtils.isNotEmpty(varList)) {
            List<FlowHiVariable> hiVarList = varList.stream().map(FlowModelUtils::convertRH)
                    .collect(Collectors.toList());
            futureList.add(CompletableFuture.runAsync(() -> flowHiVariableDao.insertBatchSomeColumn(hiVarList)));
        }
        if (CollectionUtils.isNotEmpty(taskList)) {
            List<FlowHiTask> hiTaskList = taskList.stream().map(FlowModelUtils::convertRH)
                    .collect(Collectors.toList());
            futureList.add(CompletableFuture.runAsync(() -> flowHiTaskDao.insertBatchSomeColumn(hiTaskList)));
        }

        List<FlowRuTask> firstTaskList = taskList.stream().filter(task -> task.getOrderNum() == 1)
                .collect(Collectors.toList());
        futureList.add(CompletableFuture.runAsync(() -> FlowUtils.startTaskInHistory(flowHiTaskLogDao,firstTaskList)));

        //等待所有任务执行完成
        CompletableFuture<Void> allOf = CompletableFuture.allOf(new CompletableFuture[futureList.size()]) ; ;
        allOf.join() ;
    }
}
